#include "modbus.h"
#include <QDebug>
#include <QThread>
#include <QMessageBox>
#include <QTime>
#include <QApplication>
QByteArray recvDataSave;
QByteArray sendDataSave;
int bufDataCount=0;
Modbus::Modbus()
{
    ConnectSignalSlots();
}

bool Modbus::Open(QString portName, int baurdRate, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, QSerialPort::Parity parity)
{
    port.setPortName(portName);
    port.setBaudRate(baurdRate);
    port.setDataBits(dataBits);
    port.setStopBits(stopBits);
    port.setParity(parity);
    port.open(QSerialPort::OpenModeFlag::ReadWrite);
    if(port.isOpen())
        return true;
    else
        return false;
}

void Modbus::SetPortInfo(QString portName, int baurdRate, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, QSerialPort::Parity parity)
{
    //qDebug()<<portName<<baurdRate<<dataBits<<stopBits<<parity;
    port.setPortName(portName);
    port.setBaudRate(baurdRate);
    port.setDataBits(dataBits);
    port.setStopBits(stopBits);
    port.setParity(parity);
}

bool Modbus::Close()
{
    port.close();
    if(!port.isOpen())
        return true;
    else
        return false;
}



//CRC16计算函数
void Modbus::GetCRC(QByteArray message,QByteArray &CRC)
{
    int len=message.size();
    uint16_t wcrc=0XFFFF;//预置16位crc寄存器，初值全部为1
    uint8_t temp;//定义中间变量
    int i=0,j=0;//定义计数
    for(i=0;i<len-2;i++)//循环计算每个数据
    {
        temp=message.at(i);
        wcrc^=temp;
        for(j=0;j<8;j++){
            //判断右移出的是不是1，如果是1则与多项式进行异或。
            if(wcrc&0X0001){
                wcrc>>=1;//先将数据右移一位
                wcrc^=0XA001;//与上面的多项式进行异或
            }
            else//如果不是1，则直接移出
                wcrc>>=1;//直接移出
        }
    }

    CRC[0]=wcrc&0xff;
    CRC[1]=(wcrc>>8)&0xff;
}
void Modbus::BuildMessage(uint8_t address, uint8_t type, ushort start, ushort registers,QByteArray &message)
{
    //Array to receive CRC bytes:
    QByteArray CRC;
    CRC.resize(2);

    message[0] = address;
    message[1] = type;
    message[2] = (uint8_t)(start >> 8);
    message[3] = (uint8_t)start;
    message[4] = (uint8_t)(registers >> 8);
    message[5] = (uint8_t)registers;

    GetCRC(message,CRC);
    message[message.length() - 2] = CRC[0];
    message[message.length() - 1] = CRC[1];
}

//其实与BuildMessage是一样的只是含义不同，address对于起始寄存器地址，value对应寄存器数
void Modbus::BuildMessage_F5(uint8_t address, uint8_t type, ushort adress, ushort value, QByteArray &message)
{
    QByteArray CRC;
    CRC.resize(2);

    message[0] = address;
    message[1] = type;
    message[2] = (uint8_t)(adress >> 8);
    message[3] = (uint8_t)adress;
    message[4] = (uint8_t)(value >> 8);
    message[5] = (uint8_t)value;

    GetCRC(message,CRC);
    message[message.length() - 2] = CRC[0];
    message[message.length() - 1] = CRC[1];

}

void Modbus::GetResponse(QByteArray &response,int readLength)
{
    QTime time=QTime::currentTime();
    while (time.msecsTo(QTime::currentTime())<timeout&&response.length()<readLength)
    {
       // qDebug()<<"process event 前";
        QApplication::processEvents();
       // qDebug()<<"process event 后";
        if(readyReads.count()>0)
        {
            vectorLocker.lock();
            readyReads.pop_front();
            vectorLocker.unlock();
            QByteArray readData=port.readAll();
            response.append(readData);
        }
        QThread::msleep(1);
    }
}

void Modbus::GetResponse2(QByteArray &response, int timeouts)
{
    QTime time=QTime::currentTime();
    while (time.msecsTo(QTime::currentTime())<timeouts)
    {
        QApplication::processEvents();
        if(readyReads.count()>0)
        {
            vectorLocker.lock();
            readyReads.pop_front();
            vectorLocker.unlock();
            QByteArray readData=port.readAll();
            response.append(readData);
        }
        QThread::msleep(1);
    }
}


bool Modbus::CheckResponse(QByteArray response)
{
    if(response.length()<2)
        return false;

    QByteArray CRC;
    CRC.resize(2);
    GetCRC(response,CRC);
    if (CRC[0] == response[response.length() - 2] && CRC[1] == response[response.length() - 1])
    {
        //qDebug()<<"CRC IS SCUESS";
        return true;

    }
    else
    {
        qDebug()<<"CRC IS FAILED";
        qDebug()<<(uint8_t)CRC[0]<<(uint8_t)CRC[1]<<(uint8_t)response[response.length() - 2]<<(uint8_t)response[response.length() - 1];
        return false;
    }
}

bool Modbus::SendFc16(unsigned char address, ushort start, ushort registers, ushort* values)
{
    if (port.isOpen())
    {
        port.clear(QSerialPort::AllDirections);
        QByteArray message;
        QByteArray response;
        response.clear();
        message.resize(9 + 2 * registers);
        int readLength=8;


        //添加字节数
        message[6] = (uint8_t)(registers * 2);
        //将发送的数据存入QByteArray message发送缓存
        for (int i = 0; i < registers; i++)
        {
            message[7 + 2 * i] = (uint8_t)(values[i] >> 8);
            message[8 + 2 * i] = (uint8_t)(values[i]);
        }

        BuildMessage(address, 16, start, registers, message);
        try
        {
            port.write(message);
            port.waitForBytesWritten();
            GetResponse(response,readLength);
        }
        catch (...)
        {
            modbusStatus = "Error in write event: ";
            return false;
        }
        if (CheckResponse(response))
        {
            modbusStatus = "Write successful";
            return true;
        }
        else
        {
            modbusStatus = "CRC error";
            return false;
        }
    }
    else
    {
        modbusStatus = "Serial port not open";
        return false;
    }
}


bool Modbus::SendFc6(unsigned char address, ushort start, ushort registers, ushort* values)
{
    //Ensure port is open:
    if (port.isOpen())
    {
        //Clear in/out buffers:
        port.clear(QSerialPort::AllDirections);
        //Message is 1 addr + 1 fcn + 2 start + 2 reg + 1 count + 2 * reg vals + 2 CRC
        QByteArray message;
        message.resize(8);
        //Function 16 response is fixed at 8 bytes
        QByteArray response;
        response.resize(0);
        response.clear();

        //Add bytecount to message:
        //message[6] = (byte)(registers * 2);
        //Put write values into message prior to sending:


        QByteArray CRC;
        CRC.resize(2);

        message[0] = address;
        message[1] = (unsigned char)6;
        message[2] = (unsigned char)(start >> 8);
        message[3] = (unsigned char)start;

        for (int i = 0; i < registers; i++)
        {
            message[4 + 2 * i] = (unsigned char)(values[i] >> 8);
            message[5 + 2 * i] = (unsigned char)(values[i]);
        }
        //Build outgoing message:
        //BuildMessage(address, (byte)6, start, registers, ref message);

        GetCRC(message,CRC);
        message[6] = CRC[0];
        message[7] = CRC[1];

        //Send Modbus message to Serial Port:
        try
        {
            port.write(message);
            qDebug()<<"write message:"<<message.toHex();
            GetResponse(response,8);
            qDebug()<<"recv fc6:"<<response.toHex();
        }
        catch (...)
        {
            modbusStatus = "Error in write event: ";
            return false;
        }
        //Evaluate message:
        if (CheckResponse(response))
        {
            modbusStatus = "Write successful";
            return true;
        }
        else
        {
            modbusStatus = "CRC error";
            return false;
        }
    }
    else
    {
        modbusStatus = "Serial port not open";
        return false;
    }
}

bool Modbus::SendFc3(uint8_t address, ushort start, ushort registers,ushort *values)
{
    //qDebug()<<__FUNCTION__;
    //qDebug()<<QThread::currentThreadId()<<QThread::currentThread();
    if (port.isOpen()&&(!functionIsRunning))
    {
       // qDebug()<<"Fc3 locker in";
        functionIsRunning=true;
        locker.lock();
        //qDebug()<<"Fc3 locker in 2";
        port.clear(QSerialPort::AllDirections);

        QByteArray message,response;
        response.clear();
        response.resize(0);
        //请求只有8个字节
        message.resize(8);
        int readlength=5 + 2 * registers;

        BuildMessage(address, 3, start, registers, message);

        try
        {
            vectorLocker.lock();
            readyReads.clear();
            vectorLocker.unlock();
           // qDebug()<<"fc3 send:"+message.toHex();
            port.write(message);
            port.flush();
            port.waitForBytesWritten();
            qDebug()<<"发送数据:"<<message.toHex();
            sendDataSave=message;
            GetResponse(response,readlength);
            if(response.length()<readlength)
            {
                qDebug()<<"modbus function recv length"<<response.length();
                locker.unlock();
                qDebug()<<"收到回复(少)："<<response.toHex();

                //设置收到数据的字节数
                bufDataCount=response.length();
                bufDataCount=bufDataCount-5;
                if(bufDataCount<0)
                    bufDataCount=0;
                //设置收到数据的原始数据
                recvDataSave=response;
                functionIsRunning=false;
                return false;
            }

            //设置收到的数据的字节数
            bufDataCount=response.length();
            bufDataCount=bufDataCount-5;
            if(bufDataCount<0)
                bufDataCount=0;
            //设置收到的原始数据
            recvDataSave=response;
            qDebug()<<"收到回复："<<response.toHex();
        }
        catch (...)
        {
            modbusStatus = "Error in read event: ";
            locker.unlock();
            functionIsRunning=false;
            return false;
        }
        if (CheckResponse(response))
        {
            for (int i = 0; i < (response.length() - 5) / 2; i++)
            {
                values[i] = (uint8_t)response[2 * i + 3];
                values[i] <<= 8;
                values[i] += (uint8_t)response[2 * i + 4];
            }
            modbusStatus = "Read successful";
            locker.unlock();
            functionIsRunning=false;
            return true;
        }
        else
        {
            //校验未通过设置收到的数据为0，但要记录原始数据
            bufDataCount=0;

            modbusStatus = "CRC error";
            locker.unlock();
            functionIsRunning=false;
            return false;
        }
    }
    else
    {
        //串口未打开设置发送和收到的数据都为0
        bufDataCount=0;
        QByteArray fakeRecvData;
        fakeRecvData.clear();
        sendDataSave=fakeRecvData;
        recvDataSave=fakeRecvData;


        modbusStatus = "Serial port not open";
        qDebug()<<"----------------------------->"<<__FUNCTION__<<__LINE__<<"serial port not open";
        //functionIsRunning=false;
        return false;
    }
}

bool Modbus::  SendFc4(uint8_t address, ushort start, ushort registers, ushort *values)
{
    qDebug()<<__FUNCTION__;
    if (port.isOpen()&&(!functionIsRunning))
    {
        functionIsRunning=true;
        qDebug()<<"Fc3 locker in";
        locker.lock();
        port.clear(QSerialPort::AllDirections);

        QByteArray message,response;
        response.clear();
        response.resize(0);
        //请求只有8个字节
        message.resize(8);
        int readlength=5 + 2 * registers;

        BuildMessage(address, 4, start, registers, message);

        try
        {
            vectorLocker.lock();
            readyReads.clear();
            vectorLocker.unlock();
            port.write(message);
            port.waitForBytesWritten();
            GetResponse(response,readlength);
            if(response.length()<readlength)
            {
                qDebug()<<"modbus function recv length"<<response.length();
                locker.unlock();
                qDebug()<<"收到回复(少)："<<response.toHex();

                //设置收到数据的字节数
                bufDataCount=response.length();
                bufDataCount=bufDataCount-5;
                if(bufDataCount<0)
                    bufDataCount=0;
                //设置收到数据的原始数据
                recvDataSave=response;
                functionIsRunning=false;
                return false;
            }
            qDebug()<<"收到回复："<<response.toHex();
            //设置收到的数据的字节数
            bufDataCount=response.length();
            bufDataCount=bufDataCount-5;
            if(bufDataCount<0)
                bufDataCount=0;
            //设置收到的原始数据
            recvDataSave=response;
            qDebug()<<"收到回复："<<response.toHex();
        }
        catch (...)
        {
            modbusStatus = "Error in read event: ";
            locker.unlock();
            functionIsRunning=false;
            return false;
        }
        if (CheckResponse(response))
        {
            for (int i = 0; i < (response.length() - 5) / 2; i++)
            {
                values[i] = (uint8_t)response[2 * i + 3];
                values[i] <<= 8;
                values[i] += (uint8_t)response[2 * i + 4];
            }
            modbusStatus = "Read successful";
            locker.unlock();
            functionIsRunning=false;
            return true;
        }
        else
        {
            modbusStatus = "CRC error";
            locker.unlock();
            functionIsRunning=false;
            return false;
        }
    }
    else
    {

        bufDataCount=0;
        QByteArray fakeRecvData;
        fakeRecvData.clear();
        sendDataSave=fakeRecvData;
        recvDataSave=fakeRecvData;

        modbusStatus = "Serial port not open";
        qDebug()<<__FUNCTION__<<__LINE__<<"serial port not open";
        //functionIsRunning=false;
        return false;
    }
}

bool Modbus::SendF5(uint8_t address, ushort start, ushort value)
{
    if(port.isOpen())
    {
        qDebug()<<__LINE__;
        locker.lock();
        qDebug()<<__LINE__;
        port.clear(QSerialPort::AllDirections);
        QByteArray message,response;
        message.resize(8);
        response.clear();
        response.resize(0);
        int readlength=8;
        BuildMessage_F5(address,5,start,value,message);

        try
        {
            vectorLocker.lock();
            readyReads.clear();
            vectorLocker.unlock();
            port.write(message);
            port.waitForBytesWritten();
            GetResponse(response,readlength);
            if(response.length()<readlength)
           {
                locker.unlock();
                return false;
            }
        }
        catch (...)
        {
            locker.unlock();
            modbusStatus = "Error in read event: ";
            return false;
        }

        if (CheckResponse(response))
        {
            modbusStatus = "Read successful";
            locker.unlock();
            return true;
        }
        else
        {
            modbusStatus = "CRC error";
            locker.unlock();
            return false;
        }
    }
    else
    {
        modbusStatus = "Serial port not open";
        return false;
    }
}

bool Modbus::SendFc1(unsigned char address, ushort start, ushort registers, unsigned char *values)
{
    if(port.isOpen())
    {
        QByteArray sendData,response;
        response.resize(0);
        response.clear();

        sendData.resize(8);
        sendData.data()[0]=address;
        sendData.data()[1]=1;

        sendData.data()[2]=(start>>8)&0xff;
        sendData.data()[3]=(start&0xff);

        sendData.data()[4]=(registers>>8)&0xff;
        sendData.data()[5]=(registers&0xff);

        QByteArray CRC;
        CRC.resize(2);
        GetCRC(sendData,CRC);
        sendData[sendData.length() - 2] = CRC[0];
        sendData[sendData.length() - 1] = CRC[1];

        int readLength=5+(registers+7)/8;

        try
        {
            vectorLocker.lock();
            readyReads.clear();
            vectorLocker.unlock();
            //qDebug()<<sendData.toHex();
            port.write(sendData);
            port.waitForBytesWritten();
            GetResponse(response,readLength);
            if(response.length()<readLength)
            {
                qDebug()<<"1:"<<response.length();
                return false;
            }
            unsigned char bytes=response.data()[2];
            if(bytes==1)
            {
                *values=response.data()[3];
                return true;
            }
        }
        catch (...)
        {
            modbusStatus = "Error in read event: ";
            return false;
        }

    }
    else
    {
        //qDebug()<<"port is not open";
        return false;
    }
    return  false;
}

bool Modbus::SendFc2(unsigned char address, ushort start, ushort registers, unsigned char *values)
{

    if(port.isOpen())
    {
        if(locker.tryLock())
        {
            QByteArray sendData,response;
            response.resize(0);
            response.clear();

            sendData.resize(8);
            sendData.data()[0]=address;
            sendData.data()[1]=2;

            sendData.data()[2]=(start>>8)&0xff;
            sendData.data()[3]=(start&0xff);

            sendData.data()[4]=(registers>>8)&0xff;
            sendData.data()[5]=(registers&0xff);

            QByteArray CRC;
            CRC.resize(2);
            GetCRC(sendData,CRC);
            sendData[sendData.length() - 2] = CRC[0];
            sendData[sendData.length() - 1] = CRC[1];

            int readLength=5+(registers+7)/8;

            try
            {
                vectorLocker.lock();
                readyReads.clear();
                vectorLocker.unlock();
                //qDebug()<<sendData.toHex();
                port.write(sendData);
                port.waitForBytesWritten();
                GetResponse(response,readLength);
                if(response.length()<readLength)
                {
                    qDebug()<<"2:"<<response.length();
                    locker.unlock();
                    return false;
                }
                unsigned char bytes=response.data()[2];
                if(bytes==1&&response.data()[1]==0x02)
                {
                    *values=response.data()[3];
                }
                locker.unlock();
                return true;
            }
            catch (...)
            {
                modbusStatus = "Error in read event: ";
                locker.unlock();
                return false;
            }

        }
    }
    else
    {
        //qDebug()<<"port is not open";
        return false;
    }
    return  false;
}

void Modbus::SendReadFunction(QByteArray sendData,int timeouts,QByteArray &recvData)
{
    if(port.isOpen())
    {
        port.write(sendData);
        port.waitForBytesWritten();
        GetResponse2(recvData,timeouts);
        qDebug()<<"Debug Write"<<sendData.toHex()<<"time out="<<timeouts;
        qDebug()<<"Debug Read"<<recvData.toHex();
    }
    else
    {
        qDebug()<<"port is not open";
    }
}

void Modbus::ConnectSignalSlots()
{
    connect(&port,SIGNAL(readyRead()),this,SLOT(SetComDataReady()));
}


void Modbus::SetComDataReady()
{
    vectorLocker.lock();
    readyReads.append(1);
    vectorLocker.unlock();
}
